package com.dylon.baseStudy;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CompletableFutureTest {

    /* CompletableFuture JDK1.8版本新引入的类
    *    实现接口 Future<T>, CompletionStage<T>
    *        CompletionStage 接口用于支持完成时触发相关函数和操作
    * */

    /** 简单示例 */
    public static void simpleExample(){
        try {
            CompletableFuture<String> future = new CompletableFuture<>();
            new Thread(()-> {
                System.out.println("CompletableFuture 可以控制这个任务的执行");
                try {
                    TimeUnit.SECONDS.sleep(3L);
                }catch (Exception e){
                    e.printStackTrace();
                }
                future.complete("返回结果"); // complete方法意思就是这个任务完成了需要返回的结果，结果为泛型数据
            }).start();

            System.out.println("time1:"+ System.currentTimeMillis());
            System.out.println(future.get()); // 获取返回的结果
            System.out.println("time2:"+ System.currentTimeMillis());
        } catch (Exception e ){
            e.printStackTrace();
        }
    }


    /*
    CompletableFuture 中带有Async就是异步执行的意思，也是一个completableFuture对象代表着一个任务这个原则
      异步方法都可以指定一个线程池作为任务的运行环境，如果没有指定就会使用 ForkJoinPool 线程池来执行
     */

    /** supplyAsync 的使用例子
     *      supply是持有返回值的，为守护线程
     */
    public static void supplyAsyncTest(){
        try {
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.submit(() -> {
                System.out.println("executorService 是否为守护线程 :" + Thread.currentThread().isDaemon());
                return null;
            });

            final CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
                System.out.println("CompletableFuture supplyAsync");
                System.out.println("supplyAsync 是否为守护线程 " + Thread.currentThread().isDaemon());
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("CompletableFuture executed by forkJoinPool");
                return "supplyAsync===result1";
            });

            final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                System.out.println("CompletableFuture supplyAsync with executor");
                System.out.println("supplyAsync 使用executorService 时是否为守护线程 : " + Thread.currentThread().isDaemon());
                return "supplyAsync===result2";
            }, executorService);

            System.out.println("completableFuture result: "+ completableFuture.get());
            System.out.println("future result: "+ future.get());

            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** runAsync 的使用例子
     *      run无返回值，为守护线程
     */
    public static void runAsyncTest(){
        try {
            ExecutorService executorService = Executors.newCachedThreadPool();

            final CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                System.out.println("CompletableFuture runAsync");
                System.out.println("runAsync 是否为守护线程 " + Thread.currentThread().isDaemon());
            });

            final CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                System.out.println("CompletableFuture runAsync with executor");
                System.out.println("runAsync 使用executorService 时是否为守护线程 : " + Thread.currentThread().isDaemon());
            }, executorService);

            System.out.println("completableFuture result: "+ completableFuture.get());
            System.out.println("future result: "+ future.get());

            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** allOf&anyOf
     * 两个方法的入参是一个completableFuture组
     *  allOf就是所有任务都完成时返回,但是是个Void的返回值。
     *  anyOf是当入参的completableFuture组中有一个任务执行完毕就返回,返回结果是第一个完成的任务的结果。
     * */
    public static void allOfAndAnyOfTest(){
        try {
            final CompletableFuture<String> futureOne = CompletableFuture.supplyAsync(() -> {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "futureOneResult";
            });
            final CompletableFuture<String> futureTwo = CompletableFuture.supplyAsync(() -> {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "futureTwoResult";
            });
            CompletableFuture future = CompletableFuture.allOf(futureOne, futureTwo);
            System.out.println(future.get());
    //        CompletableFuture completableFuture = CompletableFuture.anyOf(futureOne, futureTwo);
    //        System.out.println(completableFuture.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** getNow  执行方法的时候任务执行完了就返回任务的结果，如果任务没有执行完就返回你的入参，不会阻塞等待最终结果 */
    public static void getNowTest(){
        try {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    System.out.println("futureTwo InterruptedException");
                }
                return "result";
            });

            String res = future.getNow("now");
            System.out.println(res);
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** whenXXX，在一个任务执行完成之后调用的方法
     *    whenComplete、whenCompleteAsync、whenCompleteAsync用自定义Executor
     */
    public static void whenCompleteTest(){
        try {
            CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()-> {
                System.out.println("first task execute");
                int a = 1/0;
                return "first";
            });
            completableFuture.whenComplete((s , e) -> {   // s,e 分别为上一个task 的 结果和异常信息
                System.out.println("twice task execute");
                System.out.println("first task result: >> " + s);
                System.out.println("first task exception: " + e);
            });

            Thread.sleep(1000);
            System.out.println(completableFuture.get());
            System.out.println("all finish");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /* thenXXX ，同样是上一个任务结束后然后继续执行下一个任务
     *    基本上分为 异不异步 和 加不加自定义Executor
     */

    /** 上一个任务的结果 传到下一个任务
     */
    public static void thenComposeTest(){
        try {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> "first");

            CompletableFuture<String> future2 = future.thenCompose(s -> CompletableFuture.supplyAsync(()-> s + "- twice"));

            System.out.println(future2.get());
        } catch (Exception e){
            e.printStackTrace();
        }
    }
    /** 组合两个任务 结果 */
    public static void thenCombineTest(){
        try {
            CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()-> "first");

            CompletableFuture<String> future2 = future1.thenCombine(CompletableFuture.supplyAsync(()-> "twice"),
                    (s1,s2) -> s1+" - "+s2);

            System.out.println(future2.get());
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /** 多任务执行 等待返回结果*/
    public static void moreTask(){
        try {
            List<String> string = new ArrayList<>();
            string.add("1");
            CompletableFuture[] futures = string.stream()
                    .map(i -> CompletableFuture.supplyAsync(() -> add(i))).toArray(CompletableFuture[]::new);
            CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futures);
            completableFuture.get(30L, TimeUnit.MINUTES);
            for (CompletableFuture future: futures) {
                System.out.println(future.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static String add(String i){
        return i+"10";
    }


    public static void main(String[] args) {
//        simpleExample();
//        supplyAsyncTest();
//        runAsyncTest();
//        allOfAndAnyOfTest();
//        getNowTest();
//        whenCompleteTest();
//        thenComposeTest();
        thenCombineTest();
    }
}
